/**
 * @file call_log.c
 *
 */

/*********************
*      INCLUDES
*********************/
#include "lv_watch.h"

#if USE_LV_WATCH_CALL_LOG != 0

/*********************
*      DEFINES
*********************/

/**********************
*      TYPEDEFS
**********************/

/**********************
*  STATIC PROTOTYPES
**********************/
static void call_log_prepare_destory(lv_obj_t * activity_obj);
static lv_call_log_obj_ext_t * call_log_get_ext(void);
static lv_obj_t *  call_log_no_log_info_create(lv_obj_t * obj);
static nv_watch_call_log_t * call_log_read_nvm(void);
static void call_log_write_nvm(nv_watch_call_log_t * data);
static uint8_t call_log_get_log_num(nv_watch_call_log_t * data);
static void call_log_log_btn_event_cb(lv_obj_t * btn, lv_event_t e);
static void call_log_del_btn_event_cb(lv_obj_t * btn, lv_event_t e);
static void call_log_ll_init(void);
static void call_log_ll_destroy(void);
static lv_obj_t * call_log_list_create(lv_obj_t * obj);
static void call_log_content_create(lv_obj_t * list, uint8_t call_log_num, nv_watch_call_log_t * call_log_list);
static void call_log_delete_create(lv_obj_t * list);
static void call_log_update_call_log_ll(uint8_t call_log_num, nv_watch_call_log_t * call_log_list);

/**********************
*  STATIC VARIABLES
**********************/
const void * status[] = {
            (void *)ICON_CALL_LOG_OUTGOING_CALL,
            (void *)ICON_CALL_LOG_INCOMING_CALL,
            (void *)ICON_CALL_LOG_MISSED_CALL,
            (void *)ICON_CALL_LOG_INCOMING_CALL,
};

/**********************
*      MACROS
**********************/

/**********************
 *   GLOBAL FUNCTIONS
 ***********************/
lv_obj_t * call_log_create(lv_obj_t * activity_obj)
{
    if(NULL == activity_obj) {
        lv_watch_activity_ext_t activity_ext;
        memset(&activity_ext, 0, sizeof(lv_watch_activity_ext_t));
        activity_ext.actId = ACT_ID_CALL_LOG;
        activity_ext.create = call_log_create;
        activity_ext.prepare_destory = call_log_prepare_destory;
        activity_obj = lv_watch_creat_activity_obj(&activity_ext);
        LV_ASSERT_MEM(activity_obj);
        if(NULL == activity_obj) return NULL;
    }

    lv_obj_t * obj = lv_watch_obj_create(activity_obj);
    LV_ASSERT_MEM(obj);
    if(NULL == obj) return NULL;

    lv_call_log_obj_ext_t * ext = lv_obj_allocate_ext_attr(obj, sizeof(lv_call_log_obj_ext_t));
    LV_ASSERT_MEM(ext);
    if(NULL == ext) return NULL;
    ext->list = NULL;
    ext->label_tip = NULL;
    ext->phone_number_list = NULL;

    if(setting_is_flying_mode()) {
        lv_obj_t * label = lv_label_create(obj, NULL);
        lv_obj_add_style(label, LV_OBJ_PART_MAIN, &lv_watch_font20);
        lv_label_set_align(label, LV_LABEL_ALIGN_CENTER);
        lv_obj_set_click(label, false);
        lv_label_set_long_mode(label, LV_LABEL_LONG_BREAK);
        lv_obj_set_width(label, lv_obj_get_width(obj) - 50);
        lv_label_set_text_id(label, WATCH_TEXT_ID_PLEASE_TURN_OFF_FLYING_MODE);
        lv_obj_align(label, obj, LV_ALIGN_CENTER, 0, 0);
        return obj;
    }

    nv_watch_call_log_t * nvm_call_log_list = call_log_read_nvm();
    if(NULL == nvm_call_log_list) return NULL;
    uint8_t call_log_num = call_log_get_log_num(nvm_call_log_list);

    if(0 == call_log_num) {
        ext->label_tip = call_log_no_log_info_create(obj);
    } else {
        ext->list = call_log_list_create(obj);
        call_log_content_create(ext->list, call_log_num, nvm_call_log_list);
        call_log_delete_create(ext->list);
        call_log_ll_init();
        call_log_update_call_log_ll(call_log_num, nvm_call_log_list);
    }

    if(nvm_call_log_list) {
        lv_mem_free(nvm_call_log_list);
        nvm_call_log_list = NULL;
    }

    return obj;
}

void call_log_create_event_cb(lv_obj_t * btn, lv_event_t e)
{
    (void)btn;
    if(LV_EVENT_CLICKED == e)
    {
        lv_watch_png_cache_all_free();
        lv_obj_t * obj = call_log_create(NULL);
        LV_ASSERT_MEM(obj);
        if(NULL == obj) return;
    }
}

void call_log_update_call_log_info(call_status_t call_status, char * number, hal_rtc_t *time)
{
    // read from nvm first
    nv_watch_call_log_t * nvm_call_log_list = call_log_read_nvm();
    // move call log list
    memmove(&nvm_call_log_list->info[1], &nvm_call_log_list->info[0], (NV_WATCH_MAX_CALL_LOG_NUM - 1) * sizeof(nv_watch_call_log_info_t));
    // update call log info
    memset(&nvm_call_log_list->info[0], 0, sizeof(nv_watch_call_log_info_t));
    nvm_call_log_list->info[0].call_status = call_status;
    nvm_call_log_list->info[0].month = time->tm_mon;
    nvm_call_log_list->info[0].day = time->tm_mday;
    nvm_call_log_list->info[0].hour = time->tm_hour;
    nvm_call_log_list->info[0].min = time->tm_min;
    memcpy(nvm_call_log_list->info[0].number, number, strlen(number));
    // write to nvm after updating
    call_log_write_nvm(nvm_call_log_list);
}

void call_log_ui_update(void)
{
    lv_obj_t * activity_obj = lv_watch_get_activity_obj(ACT_ID_CALL_LOG);

    if(activity_obj) {
        lv_obj_t * obj = lv_obj_get_child_back(lv_obj_get_child_back(activity_obj, NULL), NULL);
        nv_watch_call_log_t * nvm_call_log_list = call_log_read_nvm();
        if(NULL == nvm_call_log_list) return;
        uint8_t call_log_num = call_log_get_log_num(nvm_call_log_list);
        lv_call_log_obj_ext_t * ext = call_log_get_ext();
        LV_ASSERT_MEM(ext);
        call_log_ll_destroy();
        call_log_ll_init();
        call_log_update_call_log_ll(call_log_num, nvm_call_log_list);
        if(ext->list) {
            lv_list_clean(ext->list);
        } else {
            if(ext->label_tip) {
                lv_obj_del(ext->label_tip);
                ext->label_tip = NULL;
            }
            ext->list = call_log_list_create(obj);
        }
        call_log_content_create(ext->list, call_log_num, nvm_call_log_list);
        call_log_delete_create(ext->list);
        if(nvm_call_log_list) {
            lv_mem_free(nvm_call_log_list);
            nvm_call_log_list = NULL;
        }
    }
}

/**********************
 *   STATIC FUNCTIONS
 **********************/
static void call_log_prepare_destory(lv_obj_t * activity_obj)
{
    lv_watch_png_cache_all_free();
    call_log_ll_destroy();
}

static lv_call_log_obj_ext_t * call_log_get_ext(void)
{
    lv_call_log_obj_ext_t  * ext = NULL;
    lv_obj_t * watch_obj = NULL;

    lv_obj_t * activity_obj = lv_watch_get_activity_obj(ACT_ID_CALL_LOG);
    if(activity_obj) {
        lv_watch_get_child_obj(activity_obj, lv_watch_obj_signal, &watch_obj);
    }
    if(watch_obj) {
        ext = lv_obj_get_ext_attr(watch_obj);
    }
    return ext;
}

static lv_obj_t * call_log_no_log_info_create(lv_obj_t * obj)
{
    lv_obj_t * label = lv_label_create(obj, NULL);
    lv_obj_add_style(label, LV_OBJ_PART_MAIN, &lv_watch_font20);
    lv_label_set_align(label, LV_LABEL_ALIGN_CENTER);
    lv_obj_set_click(label, false);
    lv_label_set_text_id(label, WATCH_TEXT_ID_NO_CALL_LOG_INFO);
    lv_obj_align(label, obj, LV_ALIGN_CENTER, 0, 0);

    return label;
}

static lv_obj_t * call_log_list_create(lv_obj_t * obj)
{
    lv_obj_t * title = lv_label_create(obj, NULL);
    lv_obj_add_style(title, LV_LABEL_PART_MAIN, &lv_watch_font20_gray);
    lv_label_set_align(title, LV_LABEL_ALIGN_CENTER);
    lv_obj_set_click(title, false);
    lv_label_set_text_id(title, WATCH_TEXT_ID_CALL_LOG);
    lv_obj_align(title, obj, LV_ALIGN_IN_TOP_MID, 0, 10);

    lv_obj_t * list = lv_list_create(obj, NULL);
    lv_page_set_edge_flash(list, true);
    lv_obj_add_style(list, LV_LIST_PART_EDGE_FLASH, &lv_watch_cont_opa1);
    lv_obj_add_style(list, LV_LIST_PART_BG, &lv_watch_style_transp);
    lv_obj_set_size(list, LV_HOR_RES, LV_VER_RES - lv_obj_get_height(title) - LV_VER_RES / 10);
    lv_obj_align(list, title, LV_ALIGN_OUT_BOTTOM_MID, 0, 0);
    lv_watch_obj_add_element(list);

    return list;
}

static void call_log_content_create(lv_obj_t * list, uint8_t call_log_num, nv_watch_call_log_t * call_log_list)
{
    uint8_t i = 0;
    char time_str[10];
    phonebook_contact_t * contact_info = NULL;
    char * tmp_num = NULL;
    nv_watch_call_log_info_t * info = NULL;
    lv_obj_t * btn[call_log_num];
    lv_obj_t * img_contact;
    lv_obj_t * label_number;
    lv_obj_t * img_status;
    lv_obj_t * label_time;
    hal_rtc_t curr_time;
    memset(&curr_time, 0, sizeof(hal_rtc_t));
    Hal_Rtc_Gettime(&curr_time);

    for(i = 0; i < call_log_num; i++) {
        btn[i] = lv_list_add_btn(list, NULL, NULL);
        lv_btn_set_layout(btn[i], LV_LAYOUT_ROW_MID);
        lv_obj_set_event_cb(btn[i], call_log_log_btn_event_cb);
        lv_watch_set_free_num(btn[i], i);

        info = &call_log_list->info[i];
        //read phonebook for getting contact img, name
        tmp_num = (char *)lv_mem_alloc(NV_CONTACTS_MAX_NUMBER_LEN);
        memset(tmp_num, 0, NV_CONTACTS_MAX_NUMBER_LEN);
        memcpy(tmp_num, info->number, NV_CONTACTS_MAX_NUMBER_LEN);
        contact_info = phonebook_get_contact_info(tmp_num);
        tmp_num = NULL;

        img_contact = lv_img_create(btn[i], NULL);
        lv_img_set_src(img_contact, ICON_OTHER_SMALL);

        lv_obj_t * cont = lv_cont_create(btn[i], NULL);
        lv_cont_set_layout(cont, LV_LAYOUT_OFF);
        lv_obj_set_width(cont, lv_obj_get_width(btn[i]) - lv_obj_get_width(img_contact));
        lv_obj_set_height(cont, lv_obj_get_height(btn[i]));
        lv_obj_add_style(cont, LV_CONT_PART_MAIN, &lv_style_transp);
        lv_page_glue_obj(cont, true);
        lv_watch_obj_add_element(cont);

        label_number = lv_label_create(cont, NULL);
        if(!strcmp(info->number, PHONE_ANONYMOUS_NUMBER)) {
            lv_label_set_text_id(label_number, WATCH_TEXT_ID_UNKONWN);
        } else {
            lv_label_set_text(label_number, info->number);
        }
        lv_label_set_long_mode(label_number, LV_LABEL_LONG_DOT);
        lv_obj_set_width(label_number, lv_obj_get_width(btn[i]) - lv_obj_get_width(img_contact) - 20);

        if(contact_info) {
            lv_img_set_src(img_contact, contact_info->img_src_small);

            lv_label_set_text(label_number, contact_info->contact_name);
            lv_mem_free(contact_info);
            contact_info = NULL;
        }

        lv_obj_t * cont_status_time =  lv_cont_create(cont, NULL);
        lv_cont_set_layout(cont_status_time, LV_LAYOUT_ROW_MID);
        lv_cont_set_fit2(cont_status_time, LV_FIT_TIGHT, LV_FIT_TIGHT);
        lv_obj_add_style(cont_status_time, LV_CONT_PART_MAIN, &lv_style_transp);
        lv_page_glue_obj(cont_status_time, true);
        lv_watch_obj_add_element(cont_status_time);

        if(LV_BIDI_DIR_RTL == lv_obj_get_base_dir(btn[i])) {
           lv_obj_align(label_number, cont, LV_ALIGN_IN_TOP_RIGHT, -10, 5);
           lv_obj_align(cont_status_time, cont, LV_ALIGN_IN_BOTTOM_RIGHT, -20, -5);
        } else {
           lv_obj_align(label_number, cont, LV_ALIGN_IN_TOP_LEFT, 10, 5);
           lv_obj_align(cont_status_time, cont, LV_ALIGN_IN_BOTTOM_LEFT, 20, -5);
        }

        img_status = lv_img_create(cont_status_time, NULL);
        lv_img_set_src(img_status, status[info->call_status]);

        if((curr_time.tm_mon == info->month) && (curr_time.tm_mday == info->day)) {
            snprintf(time_str, 10, "%02d:%02d", info->hour, info->min);
        } else {
            snprintf(time_str, 10, "%02d/%02d", info->month, info->day);
        }
        label_time = lv_label_create(cont_status_time, NULL);
        lv_label_set_text(label_time, time_str);
        lv_obj_set_base_dir(label_time, LV_BIDI_DIR_LTR);

        lv_watch_obj_add_element(btn[i]);
    }
}

static void call_log_delete_create(lv_obj_t * list)
{
    lv_obj_t * btn_del = lv_list_add_btn(list, NULL, NULL);
    lv_btn_set_layout(btn_del, LV_LAYOUT_OFF);
    lv_obj_set_event_cb(btn_del, call_log_del_btn_event_cb);
    lv_obj_t * label_del = lv_label_create(btn_del, NULL);
    lv_label_set_text_id(label_del, WATCH_TEXT_ID_DELETE_ALL);
    lv_obj_set_width(label_del, lv_obj_get_width(btn_del) - 40);
    lv_obj_add_style(label_del, LV_LABEL_PART_MAIN, &lv_watch_font20_yellow);
    lv_obj_align(label_del, btn_del, LV_ALIGN_IN_TOP_MID, 0, 0);
    lv_watch_obj_add_element(btn_del);
}

static nv_watch_call_log_t * call_log_read_nvm(void)
{
    uint32_t length = sizeof(nv_watch_call_log_t);
    nv_watch_call_log_t * data = (nv_watch_call_log_t *)lv_mem_alloc(length);
    memset(data, 0, length);
    if(length != UI_NV_Read_Req(NV_SECTION_UI_CALL_LOG, 0, length, (uint8_t *)data)) {
        printf("%s: Occur error when reading call log information from NVM\n", __FUNCTION__);
        lv_mem_free(data);
        return NULL;
    }
    return data;
}

static void call_log_write_nvm(nv_watch_call_log_t * data)
{
    if(NULL == data) return;

    uint32_t length = sizeof(nv_watch_call_log_t);
    if(length != UI_NV_Write_Req(NV_SECTION_UI_CALL_LOG, 0, length, (uint8_t *)data)) {
        printf("%s: Occur error when writing call log information to NVM\n", __FUNCTION__);
        return;
    }
    lv_mem_free(data);
}

static uint8_t call_log_get_log_num(nv_watch_call_log_t * data)
{
    uint8_t i = 0;
    for(i = 0; i < NV_WATCH_MAX_CALL_LOG_NUM; i++) {
        if('\0' == data->info[i].number[0]) {
            break;
        }
    }
    return i;
}

static void call_log_log_btn_event_cb(lv_obj_t * btn, lv_event_t e)
{
    if(LV_EVENT_CLICKED != e) return;

    lv_call_log_obj_ext_t * ext = call_log_get_ext();
    LV_ASSERT_MEM(ext);

    uint8_t index = lv_obj_get_user_data(btn).user_num;

    call_log_number_info_t * node = NULL;
    node = _lv_ll_get_head(ext->phone_number_list);
    while(node) {
        if(index == node->index) {
            printf("%s: mo start\n", __FUNCTION__);
            uint8_t length = strlen(node->phone_number);
            char * number_mo = (char *)Hal_Mem_Alloc(length + 1);
            memset(number_mo, 0, length + 1);
            memcpy(number_mo, node->phone_number, length);
            phone_voice_call_req(number_mo);
            break;
        } else {
            node = _lv_ll_get_next(ext->phone_number_list, node);
        }
    }
}

static void call_log_del_btn_event_cb(lv_obj_t * btn, lv_event_t e)
{
    if(LV_EVENT_CLICKED != e) return;

    lv_call_log_obj_ext_t * ext = call_log_get_ext();
    LV_ASSERT_MEM(ext);

    uint32_t length = sizeof(nv_watch_call_log_t);
    nv_watch_call_log_t * call_log_list = (nv_watch_call_log_t *)lv_mem_alloc(length);
    memset(call_log_list, 0, length);
    call_log_write_nvm(call_log_list);
    call_log_ll_destroy();

    lv_obj_t * obj = lv_obj_get_parent(ext->list);
    lv_obj_t * title = lv_obj_get_child_back(obj, NULL);
    lv_obj_del(title);
    lv_obj_del(ext->list);
    ext->list = NULL;

    ext->label_tip = call_log_no_log_info_create(obj);
}

static void call_log_ll_init(void)
{
    lv_call_log_obj_ext_t * ext = call_log_get_ext();
    LV_ASSERT_MEM(ext);

    if(NULL == ext->phone_number_list) {
        ext->phone_number_list = (lv_ll_t *)lv_mem_alloc(sizeof(lv_ll_t));
        memset(ext->phone_number_list, 0, sizeof(lv_ll_t));
        _lv_ll_init(ext->phone_number_list, sizeof(call_log_number_info_t));
    }
}

static void call_log_ll_destroy(void)
{
    lv_call_log_obj_ext_t * ext = call_log_get_ext();
    LV_ASSERT_MEM(ext);
    call_log_number_info_t * node = NULL;
    call_log_number_info_t * next_node = NULL;

    if(ext->phone_number_list) {
        node = (call_log_number_info_t *)_lv_ll_get_head(ext->phone_number_list);
        while(node) {
            //next node
            next_node = (call_log_number_info_t *)_lv_ll_get_next(ext->phone_number_list, node);
            if(node->phone_number) {
                lv_mem_free(node->phone_number);
                node->phone_number = NULL;
            }
            _lv_ll_remove(ext->phone_number_list, node);
            lv_mem_free(node);
            node = next_node;
        }
        lv_mem_free(ext->phone_number_list);
        ext->phone_number_list = NULL;
    }
}

static void call_log_update_call_log_ll(uint8_t call_log_num, nv_watch_call_log_t * call_log_list)
{
    lv_call_log_obj_ext_t * ext = call_log_get_ext();
    LV_ASSERT_MEM(ext);

    uint8_t i = 0;
    call_log_number_info_t * node = NULL;
    nv_watch_call_log_info_t * info = NULL;

    for(i = 0; i < call_log_num; i++) {
        info = &call_log_list->info[i];
        node = (call_log_number_info_t *)_lv_ll_ins_tail(ext->phone_number_list);
        node->index = i;
        node->phone_number = (char *)lv_mem_alloc(NV_CONTACTS_MAX_NUMBER_LEN);
        memset(node->phone_number, 0, NV_CONTACTS_MAX_NUMBER_LEN);
        memcpy(node->phone_number, info->number, NV_CONTACTS_MAX_NUMBER_LEN);
    }
}

#endif /*USE_LV_WATCH_CALL_LOG*/
